unit uGlsONB;
(*
  Description: This is the implementation of an Orthonormal Base class.
  Started by Ton van den Heuvel, 15-08-2002
*)

interface

uses
  uGlsVector,
  uGlsMatrix;

type
  TONB = class
  private
    Fu: TVector3d;
    Fv: TVector3d;
    Fw: TVector3d;
    // FLCTransformMatrix is the matrix used to take the ONB defined by
    // Fu, Fv and Fw to the standard canonical ONB defined by x, y and z.
    FLCTransformMatrix: TGLMatrix;
    // FCLTransformMatrix is the matrix used to take the canonical ONB
    // defined by x, y and z to the ONB defined by Fu, Fv and Fw.
    FCLTransformMatrix: TGLMatrix;
  public
    property u: TVector3d read Fu write Fu;
    property v: TVector3d read Fv write Fv;
    property w: TVector3d read Fw write Fw;
    property LCTransformMatrix: TGLMatrix read FLCTransformMatrix
      write FLCTransformMatrix;
    property CLTransformMatrix: TGLMatrix read FCLTransformMatrix
      write FCLTransformMatrix;

    constructor CreateStandard;
    { Pre: True
      Post: u is the standard x vector (1, 0, 0)
      v is the standard y vector (0, 1, 0)
      w is the standard z vector (0, 0, 1) }

    constructor CreateFromUV(a, b: TVector3d);
    { Pre: True
      Post: u is parallel to a
      v is in the plane of a and b
      w is parallel to u x v }
    constructor CreateFromVW(a, b: TVector3d);
    { Pre: True
      Post: v is parallel to a
      w is in the plane of a and b
      u is parallel to v x w }
    constructor CreateFromWV(a, b: TVector3d);
    { Pre: True
      Post: w is parallel to a
      v is in the plane of a and b
      u is parallel to w x v }
    constructor CreateFromUW(a, b: TVector3d);
    { Pre: True
      Post: u is parallel to a
      w is in the plane of a and b
      v is parallel to u x w }
    constructor CreateFromWU(a, b: TVector3d);
    { Pre: True
      Post: w is parallel to a
      u is in the plane of a and b
      v is parallel to w x u }
    procedure SetTransformMatrices;

    destructor Destroy; override;

    procedure Assign(AONB: TONB);
  end;

implementation

{ TONB }

constructor TONB.CreateStandard;
{ Pre: True
  Post: u is the standard x vector (1, 0, 0)
  v is the standard y vector (0, 1, 0)
  w is the standard z vector (0, 0, 1) }
begin
  inherited Create;
  Fu := TVector3d.Create(1, 0, 0);
  Fv := TVector3d.Create(0, 1, 0);
  Fw := TVector3d.Create(0, 0, 1);

  { Note: setting transformation matrices for the canonical coordinate system
    is actually quite useless, but is done here to maintain consistency ;) }
  SetTransformMatrices;
end;

constructor TONB.CreateFromUV(a, b: TVector3d);
{ Pre: True
  Post: u is parallel to a
  v is in the plane of a and b
  w is parallel to u x v }
begin
  inherited Create;
  { Create Fu parallel to a }
  Fu := TVector3d.Create;
  Fu.Assign(a);
  Fu.Normalize;
  { Create Fw parallel to a x b }
  Fw := a.CrossProduct(b);
  Fw.Normalize;
  { Create Fv in the plane of a and b }
  Fv := Fw.CrossProduct(Fu);

  SetTransformMatrices;
end;

constructor TONB.CreateFromVW(a, b: TVector3d);
{ Pre: True
  Post: v is parallel to a
  w is in the plane of a and b
  u is parallel to v x w }
begin
  inherited Create;
  { Create Fv parallel to a }
  Fv := TVector3d.Create;
  Fv.Assign(a);
  Fv.Normalize;
  { Create Fu parallel to a x b }
  Fu := a.CrossProduct(b);
  Fu.Normalize;
  { Create Fw in the plane of a and b }
  Fw := Fu.CrossProduct(Fv);

  SetTransformMatrices;
end;

constructor TONB.CreateFromUW(a, b: TVector3d);
{ Pre: True
  Post: u is parallel to a
  w is in the plane of a and b
  v is parallel to u x w }
begin
  inherited Create;
  { Create Fu parallel to a }
  Fu := TVector3d.Create;
  Fu.Assign(a);
  Fu.Normalize;
  { Create Fv parallel to a x b }
  Fv := a.CrossProduct(b);
  Fv.Normalize;
  { Create Fw in the plane of a and b }
  Fw := Fv.CrossProduct(Fu);

  SetTransformMatrices;
end;

constructor TONB.CreateFromWU(a, b: TVector3d);
{ Pre: True
  Post: w is parallel to a
  u is in the plane of a and b
  v is parallel to w x u }
begin
  { Create Fw parallel to a }
  Fw := TVector3d.Create;
  Fw.Assign(a);
  Fw.Normalize;
  { Create Fv parallel to a x b }
  Fv := a.CrossProduct(b);
  Fv.Normalize;
  { Create Fu in the plane of a and b }
  Fu := Fv.CrossProduct(Fw);

  SetTransformMatrices;
end;

constructor TONB.CreateFromWV(a, b: TVector3d);
{ Pre: True
  Post: w is parallel to a
  v is in the plane of a and b
  u is parallel to w x v }

begin
  inherited Create;
  { Create Fw parallel to a }
  Fw := TVector3d.Create;
  Fw.Assign(a);
  Fw.Normalize;
  { Create Fu parallel to a x b }
  Fu := a.CrossProduct(b);
  Fu.Normalize;
  { Create Fv in the plane of a and b }
  Fv := Fu.CrossProduct(Fw);

  SetTransformMatrices;
end;

destructor TONB.Destroy;
begin
  Fu.Destroy;
  Fv.Destroy;
  Fw.Destroy;
  FCLTransformMatrix.Destroy;
  FLCTransformMatrix.Destroy;
  inherited Destroy;
end;

procedure TONB.SetTransformMatrices;
begin
  FLCTransformMatrix := TGLMatrix.Create;
  FCLTransformMatrix := TGLMatrix.Create;
  with FLCTransformMatrix do
  begin
    SetIdentityMatrix;
    SetColumn(0, Fu);
    SetColumn(1, Fv);
    SetColumn(2, Fw);
  end;
  with FCLTransformMatrix do
  begin
    SetIdentityMatrix;
    SetRow(0, Fu);
    SetRow(1, Fv);
    SetRow(2, Fw);
  end;
end;

procedure TONB.Assign(AONB: TONB);
begin
  { Clean up present u, v, w vectors and transformation matrices }
  Fu.Free;
  Fv.Free;
  Fw.Free;
  FLCTransformMatrix.Free;
  FCLTransformMatrix.Free;
  { Create new objects and assign the values from AONB }
  Fu := TVector3d.Create;
  Fu.Assign(AONB.u);
  Fv := TVector3d.Create;
  Fv.Assign(AONB.v);
  Fw := TVector3d.Create;
  Fw.Assign(AONB.w);
  FLCTransformMatrix := TGLMatrix.Create;
  FLCTransformMatrix.Assign(AONB.FLCTransformMatrix);
  FCLTransformMatrix := TGLMatrix.Create;
  FCLTransformMatrix.Assign(AONB.FCLTransformMatrix);
end;

end.
